package team.southcat.wsyygh.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.aspectj.weaver.ast.Or;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import team.southcat.wsyygh.common.client.AreaFeignClient;
import team.southcat.wsyygh.common.exception.WsyyghException;
import team.southcat.wsyygh.common.result.ResultCodeEnum;
import team.southcat.wsyygh.hospital.client.HospitalFeignClient;
import team.southcat.wsyygh.hospital.client.ScheduleFeignClient;
import team.southcat.wsyygh.model.enums.OrderStatusEnum;
import team.southcat.wsyygh.model.pojo.Msm.MsmVo;
import team.southcat.wsyygh.model.pojo.Msm.OrderMqVo;
import team.southcat.wsyygh.model.pojo.common.Area;
import team.southcat.wsyygh.model.pojo.hospital.Schedule;
import team.southcat.wsyygh.model.pojo.order.*;
import team.southcat.wsyygh.model.pojo.user.Patient;
import team.southcat.wsyygh.model.pojo.user.PatientVo;
import team.southcat.wsyygh.order.mapper.OrderMapper;
import team.southcat.wsyygh.order.service.OrderService;
import team.southcat.wsyygh.rabbit.constant.MqConst;
import team.southcat.wsyygh.rabbit.service.RabbitService;
import team.southcat.wsyygh.user.client.PatientFeignClient;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author QiuSiYi
 * @since 2023-04-20
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private AreaFeignClient areaFeignClient;

    @Autowired
    private PatientFeignClient patientFeignClient;

    @Autowired
    private HospitalFeignClient hospitalFeignClient;

    @Autowired
    private ScheduleFeignClient scheduleFeignClient;

    @Autowired
    private RabbitService rabbitService;

    @Override
    public Page getOrderPageList(Integer page, Integer pageSize, OrderVo orderVo) {
        //分页构造器,传入页码和大小
        Page<Order> pageInfo = new Page<>(page, pageSize);


        //条件构造器
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();

        //通过科室名称查询订单
        queryWrapper.like(orderVo.getDepartmentName() != null, Order::getDepartmentName, orderVo.getDepartmentName());

        //通过订单号查询订单
        queryWrapper.eq(orderVo.getOutTradeNo() != null, Order::getOutTradeNo, orderVo.getOutTradeNo());

        //通过就诊人名称查询订单
        queryWrapper.like(orderVo.getPatientName() != null, Order::getPatientName, orderVo.getPatientName());

        //执行查询
        this.page(pageInfo, queryWrapper);
        //对象拷贝为Vo对象Page
        Page<OrderVo> voPage = new Page<>();
        BeanUtils.copyProperties(pageInfo, voPage);

        //列出数据并转换成值
        List<Order> records = pageInfo.getRecords();

        //使用流转换
        List<OrderVo> orderVos = records.stream().map((order1) -> {
            OrderVo orderVo1 = this.swtichVo(order1);
            return orderVo1;
        }).collect(Collectors.toList());

        //放数据返回
        voPage.setRecords(orderVos);
        return voPage;
    }

    private OrderVo swtichVo(Order order1) {
        OrderVo orderVo1 = new OrderVo();
        BeanUtils.copyProperties(order1, orderVo1);


        //将查出来的排班日期转换成标准格式
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String workDate = sdf.format(orderVo1.getWorkDate());
        //将预约的时间转换成上午或下午
        String workTime = null;
        if (orderVo1.getWorkTime() == 0) {
            workTime = "上午";
        } else if (orderVo1.getWorkTime() == 1) {
            workTime = "下午";
        }
        orderVo1.setWorkDateTime(workDate + " " + workTime);

        //将状态转换为需要的订单状态展示
        switch (orderVo1.getStatus()) {
            case 0:
                orderVo1.setOrderStatus("预约成功，待支付");
                break;
            case 1:
                orderVo1.setOrderStatus("已支付");
                break;
            case 2:
                orderVo1.setOrderStatus("已取号");
                break;
            case -1:
                orderVo1.setOrderStatus("取消预约");
        }

        return orderVo1;
    }

    @Override
    public OrderVo selectById(long id) {
        Order order = baseMapper.selectById(id);
        OrderVo orderVo = new OrderVo();
        BeanUtils.copyProperties(order, orderVo);


        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String workDate = sdf.format(orderVo.getWorkDate());
        //将预约的时间转换成上午或下午
        String workTime = null;
        if (orderVo.getWorkTime() == 0) {
            workTime = "上午";
        } else if (orderVo.getWorkTime() == 1) {
            workTime = "下午";
        }
        orderVo.setWorkDateTime(workDate + " " + workTime);

        //将状态转换为需要的订单状态展示
        switch (orderVo.getStatus()) {
            case 0:
                orderVo.setOrderStatus("预约成功，待支付");
                break;
            case 1:
                orderVo.setOrderStatus("已支付");
                break;
            case 2:
                orderVo.setOrderStatus("已取号");
                break;
            case -1:
                orderVo.setOrderStatus("取消预约");
        }

        return orderVo;
    }

    @Override
    public PatientVo selectPatientById(Long patientId) {
        Object patientObject = patientFeignClient.getPatientById(patientId).getData();
        Patient patient = JSONObject.parseObject(JSON.toJSONString(patientObject), Patient.class);
        PatientVo patientVo = new PatientVo();
        BeanUtils.copyProperties(patient, patientVo);

        if (patientVo.getIsMarry() == 0) {
            patientVo.setMarried("否");
        } else if (patientVo.getIsMarry() == 1) {
            patientVo.setMarried("是");
        }

        if (patientVo.getGender() == 0) {
            patientVo.setGenderName("女");
        } else if (patientVo.getGender() == 1) {
            patientVo.setGenderName("男");
        }

        Object provinceObject = areaFeignClient.getById(patient.getProvinceId()).getData();
        Object cityObject = areaFeignClient.getById(patient.getCityId()).getData();
        Object districtObject = areaFeignClient.getById(patient.getDistrictId()).getData();

        Area province = JSONObject.parseObject(JSON.toJSONString(provinceObject), Area.class);
        Area city = JSONObject.parseObject(JSON.toJSONString(cityObject), Area.class);
        Area district = JSONObject.parseObject(JSON.toJSONString(districtObject), Area.class);

        //设置地址
        patientVo.setProvince(province.getName());
        patientVo.setCity(city.getName());
        patientVo.setDistrict(district.getName());
        return patientVo;
    }


    //预约统计方法
    @Override
    public Map<String, Object> getCountMap(OrderCountQueryVo orderCountQueryVo) {
        //调用mapper方法得到数据
        List<OrderCountVo> orderCountVosList = baseMapper.selectOrderCount(orderCountQueryVo);

        //获取x需要的数据，日期数据，list集合
        List<String> dateList = orderCountVosList.stream().map(OrderCountVo::getWorkDate).collect(Collectors.toList());

        //获取y需要的数据，具体数量，list集合
        List<Integer> countList = orderCountVosList.stream().map(OrderCountVo::getCount).collect(Collectors.toList());

        Map<String, Object> map = new HashMap<>();
        map.put("dateList", dateList);
        map.put("countList", countList);
        return map;
    }

    //保存订单
    @Override
    public Long saveOrder(String scheduleId, Long patientId) {
        //获取就诊人信息
        Patient patient = patientFeignClient.getById(patientId);

        //获取排班相关信息
        ScheduleOrderVo scheduleOrderVo = hospitalFeignClient.getScheduleOrderVo(scheduleId);
        Schedule schedule = scheduleFeignClient.getById(Long.parseLong(scheduleId));

        //判断当前时间是否还可以预约
        //当前是 开始时间之后，截至时间之前
        if (new DateTime(scheduleOrderVo.getStartTime()).isAfterNow() || new DateTime(scheduleOrderVo.getEndTime()).isBeforeNow()) {
            throw new WsyyghException(ResultCodeEnum.TIME_NO);
        }

        //重复预约
        Order getOrder =  this.getByScheduleIdAndPatientId(scheduleId, patientId);
        if (getOrder != null){
            throw new WsyyghException("同个排班只能预约一次！", 201);
        }

        //设置订单数据
        Order order = new Order();
        BeanUtils.copyProperties(scheduleOrderVo, order);

        order.setHospitalId(Long.valueOf(scheduleOrderVo.getHospitalId()));
        order.setDepartmentId(Long.valueOf(scheduleOrderVo.getDepartmentId()));
        order.setUserId(patient.getUserId());
        order.setPatientId(patientId);
        order.setPatientName(patient.getName());
        order.setPatientPhone(patient.getPhone());
        //总 - 剩 + 1
        order.setBookingNumber(schedule.getBookingCount().intValue() - schedule.getBookingSurplus().intValue() + 1);
        order.setFetchTime("0".equals(scheduleOrderVo.getWorkTime()) ? "08:30前" : "14:00前");
        order.setFetchAddress("医院内");
        order.setStatus(OrderStatusEnum.UNPAID.getStatus());
        order.setScheduleId(Long.valueOf(scheduleId));

        baseMapper.insert(order);

        //更新预约排班剩余数量
        //scheduleFeignClient.minusOne(Long.parseLong(scheduleId));

        //排班可预约数
        Integer reservedNumber = schedule.getBookingCount();
        //排班剩余预约数
        Integer availableNumber = schedule.getBookingSurplus();

        //发送mq信息更新号源和短信通知
        //发送mq，号源更新
        OrderMqVo orderMqVo = new OrderMqVo();
        orderMqVo.setScheduleId(scheduleId);
        orderMqVo.setReservedNumber(reservedNumber);
        orderMqVo.setAvailableNumber(availableNumber - 1);
        //短信提示
        MsmVo msmVo = new MsmVo();
        msmVo.setPhone(order.getPatientPhone());
        String date = new DateTime(order.getWorkDate()).toString("yyyy-MM-dd") + (order.getWorkTime() == 0 ? "上午" : "下午");

        Map<String, Object> param = new HashMap<String, Object>() {{
            put("title", order.getHospitalName() + "|" + order.getDepartmentName() + "|" + order.getTitle());
            put("amount", order.getAmount());
            put("reserveDate", date);
            put("name", order.getPatientName());
            put("quitTime", new DateTime(order.getQuitTime()).toString("yyyy-MM-dd HH:mm"));
        }};
        msmVo.setParam(param);

        orderMqVo.setMsmVo(msmVo);

        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);

        return order.getId();
    }

    //获取非取消的订单
    private Order getByScheduleIdAndPatientId(String scheduleId, Long patientId) {
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getScheduleId, scheduleId);
        queryWrapper.eq(Order::getPatientId, patientId);
        queryWrapper.ne(Order::getStatus, OrderStatusEnum.CANCLE.getStatus());
        Order order = baseMapper.selectOne(queryWrapper);
        return order;
    }

    @Override
    public Page<OrderVo> selectPage(Long page, Long limit, OrderVo orderVo) {
        Page<Order> pageInfo = new Page<>(page, limit);
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getUserId, orderVo.getUserId());
        queryWrapper.like(orderVo.getHospitalName() != null, Order::getHospitalName, orderVo.getHospitalName());
        queryWrapper.eq(orderVo.getPatientId() != null, Order::getPatientId, orderVo.getPatientId());
        queryWrapper.eq(orderVo.getStatus() != null, Order::getStatus, orderVo.getStatus());
        queryWrapper.eq(orderVo.getWorkDate() != null, Order::getWorkDate, orderVo.getWorkDate());
        queryWrapper.eq(orderVo.getCreateTime() != null, Order::getCreateTime, orderVo.getCreateTime());
        Page<Order> orderPage = baseMapper.selectPage(pageInfo, queryWrapper);
        //转换vo
        Page<OrderVo> voPage = new Page<>();
        BeanUtils.copyProperties(orderPage, voPage);

        List<Order> records = orderPage.getRecords();
        List<OrderVo> vos = records.stream().map(item -> {
            return this.swtichVo(item);
        }).collect(Collectors.toList());

        voPage.setRecords(vos);
        return voPage;
    }

    @Override
    public boolean cancelOrder(long orderId) {
        Order order = baseMapper.selectById(orderId);

        //检查退号时间
        DateTime quitTime = new DateTime(order.getQuitTime());
        if (quitTime.isBeforeNow()){
            //超过退号时间
            throw new WsyyghException(ResultCodeEnum.CANCEL_ORDER_NO);
        }

        //未支付，直接取消
        if (OrderStatusEnum.UNPAID.getStatus() == order.getStatus()){
            //修改订单状态
            order.setStatus(-1);
            order.setUpdateTime(new Date());
            baseMapper.updateById(order);
            //增加剩余预约数量
            OrderMqVo orderMqVo = new OrderMqVo();
            orderMqVo.setScheduleId(String.valueOf(order.getScheduleId()));
            Schedule schedule = scheduleFeignClient.getById(order.getScheduleId());
            orderMqVo.setReservedNumber(schedule.getBookingCount());
            orderMqVo.setAvailableNumber(schedule.getBookingSurplus() + 1);
            return true;
        }

        //已支付，先退款再取消
        if (OrderStatusEnum.PAID.getStatus() == order.getStatus()){
            //修改订单状态
            order.setStatus(-1);
            order.setUpdateTime(new Date());
            baseMapper.updateById(order);
            //增加剩余预约数量
            OrderMqVo orderMqVo = new OrderMqVo();
            orderMqVo.setScheduleId(String.valueOf(order.getScheduleId()));
            Schedule schedule = scheduleFeignClient.getById(order.getScheduleId());
            orderMqVo.setReservedNumber(schedule.getBookingCount());
            orderMqVo.setAvailableNumber(schedule.getBookingSurplus() + 1);
            // 增加退款记录
            return true;
        }

        return false;
    }

    @Override
    public boolean pay(long orderId) {
        //判断是否超过诊断时间；
        Order order = baseMapper.selectById(orderId);
        DateTime work = this.swtichDateTime(order.getWorkDate(), order.getWorkTime() == 0 ? "09:00" : "14:00");
        if (work.isBeforeNow()){
            //超过诊断时间
            throw new WsyyghException("接近或超过诊断时间，无法支付", 201);
        }

        //修改订单状态
        order.setStatus(OrderStatusEnum.PAID.getStatus());
        order.setUpdateTime(new Date());
        baseMapper.updateById(order);
        return true;
    }

    /**
     * 将Date日期（yyyy-MM-dd HH:mm）转换为DateTime
     *
     * @param date
     * @param timeString
     * @return
     */
    private DateTime swtichDateTime(Date date, String timeString) {
        String dateTimeString = new DateTime(date).toString("yyyy-MM-dd") + " " + timeString;
        DateTime dateTime = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm").parseDateTime(dateTimeString);
        return dateTime;
    }

}

